#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "constants.h"
#include "tool/stringtinylib.h"
#include "tool/linklistlib.h"
#include "instruction.h"
#include "function.h"

typedef struct SymbolNode{
	int iIndex;
	char pstrIdent [ MAX_IDENT_SIZE ];
	int iSize;
	int iStackIndex;
	int iFuncIndex;
}SymbolNode;

typedef struct LabelNode{
	int iIndex;
	char pstrIdent [ MAX_IDENT_SIZE ];
	int iTargetIndex;
	int iFuncIndex;
}LabelNode;

typedef int Token;
typedef struct Lexer  {                         // The lexical analyzer/tokenizer
	int iCurrSourceLine;                        // Current line in the source
	unsigned int iIndex0,  iIndex1;                     // Indices into the string
	Token CurrToken;                            // Current token
	char pstrCurrLexeme [ MAX_LEXEME_SIZE ];    // Current lexeme
	int iCurrLexState;                          // The current lex state

}Lexer;

typedef struct ScriptHeader{
	int iStackSize;                             // Requested stack size
	int iGlobalDataSize;			    // The size of the script's global data
	int iIsMainFuncPresent;                     // Is _Main () present?
	int iMainFuncIndex;			    // _Main ()'s function index
}ScriptHeader;

LinkedList g_FuncTable;
LinkedList g_StringTable;
LinkedList g_SymbolTable;
LinkedList g_LabelTable;
LinkedList g_HostAPICallTable;
extern InstrLookup g_InstrTable [ MAX_INSTR_LOOKUP_COUNT ];
ScriptHeader g_ScriptHeader;
int g_iIsSetStackSizeFound;
int g_iInstrStreamSize;
Instr * g_pInstrStream = NULL;
int g_iCurrInstrIndex;
int g_iSourceCodeSize=0;  
char ** g_ppstrSourceCode = NULL;
FILE * g_pSourceFile = NULL;
Lexer g_Lexer; 

int AddString ( LinkedList * pList, char * pstrString );
int AddFunc ( char * pstrName, int iEntryPoint );
void SetFuncInfo ( char * pstrName, int iParamCount, int iLocalDataSize );
FuncNode * GetFuncByName ( char * pstrName );
SymbolNode * GetSymbolByIdent ( char * Ident, int FuncIndex );
int AddSymbol ( char * pstrIdent, int iSize, int iStackIndex, int iFuncIndex );
int GetStackIndexByIdent ( char * pstrIdent, int iFuncIndex );
int GetSizeByIdent ( char * pstrIdent, int iFuncIndex );
int AddLabel ( char * pstrIdent, int iTargetIndex, int iFuncIndex );
LabelNode * GetLabelByIdent ( char * pstrIdent, int iFuncIndex );
void LoadSourceFile(char * g_pstrSourceFilename);
void StripComments ( char * pstrSourceLine );
void ExitOnError(char * msg);
void TrimWhitespace ( char * pstrString );
int SkipToNextLine ();
Token GetNextToken ();
void ResetLexer ();
char GetLookAheadChar();
void AssmblSourceFile ();
void ExitOnCodeError ( char * pstrErrorMssg );
void ExitOnCharExpectedError ( char cChar );
char * GetCurrLexeme ();
void BuildXSE (char * g_pstrExecFilename);
void Init ();
void ShutDown ();

int main(int argc, char * argv[]){

	LoadSourceFile(argv[1]);
	InitInstrTable();

//	ResetLexer ();
//	Token token = TOKEN_TYPE_INVALID;
//	while ((token=GetNextToken ()) != END_OF_TOKEN_STREAM){
//		printf("LookAheadChar=%c ", GetLookAheadChar());
	//	printf("%d \n", token);
//	}
	AssmblSourceFile ();
	BuildXSE (argv[2]);
	ShutDown ();

	return 0;

}

void Init (){
	InitInstrTable ();
	InitLinkedList ( & g_SymbolTable );
	InitLinkedList ( & g_LabelTable );
	InitLinkedList ( & g_FuncTable );
	InitLinkedList ( & g_StringTable );
	InitLinkedList ( & g_HostAPICallTable );
}

void LoadSourceFile(char * g_pstrSourceFilename){
	g_pSourceFile = fopen(g_pstrSourceFilename, "r");
        if(g_pSourceFile==NULL){
                ExitOnError("open file failed");
        }
        char c;
        while( (c=fgetc(g_pSourceFile))!=EOF  ){  
                if(c=='\n')
                        g_iSourceCodeSize ++; 
        }
	fclose ( g_pSourceFile );
	printf("has %d lines\n", g_iSourceCodeSize);

	g_pSourceFile = fopen(g_pstrSourceFilename, "r");
	if ( ! ( g_ppstrSourceCode = ( char ** ) malloc ( g_iSourceCodeSize * sizeof ( char * ) ) ) )
		ExitOnError ( "Could not allocate space for source code" );

	int iCurrLineIndex=0;
	for(; iCurrLineIndex < g_iSourceCodeSize; ++ iCurrLineIndex ){
		if ( ! ( g_ppstrSourceCode [ iCurrLineIndex ] = ( char * ) malloc ( MAX_SOURCE_LINE_SIZE + 1 ) ) )
			ExitOnError ( "Could not allocate space for source line" );

		fgets(g_ppstrSourceCode [ iCurrLineIndex ], MAX_SOURCE_LINE_SIZE, g_pSourceFile);
		StripComments ( g_ppstrSourceCode [ iCurrLineIndex ] );
		TrimWhitespace ( g_ppstrSourceCode [ iCurrLineIndex ] );
		//printf("LINE %d: %s",iCurrLineIndex, g_ppstrSourceCode [ iCurrLineIndex ]);
		//printf("%s", g_ppstrSourceCode [ iCurrLineIndex ]);
	}
	fclose ( g_pSourceFile );
}

void StripComments ( char * pstrSourceLine ){
	int iCurrCharIndex = 0;
	int iInString = 0;

	for ( ; iCurrCharIndex < strlen(pstrSourceLine); iCurrCharIndex ++ ){
		if ( pstrSourceLine[iCurrCharIndex] == '"' )
			iInString = (iInString+1)%2;

		if ( pstrSourceLine [ iCurrCharIndex ] == ';' ){
			if( iInString==0 ){
				pstrSourceLine [ iCurrCharIndex ] = '\n';
				pstrSourceLine [ iCurrCharIndex+1 ] = '\0';
				break;
			}
		}
	}
}

void TrimWhitespace ( char * pstrString ){
	int iActualStart = 0;
	int iActualEnd = strlen(pstrString) - 2;//最后一个字符必然是回车，跳过

	while(pstrString[iActualStart]!='\0' && IsCharWhitespace(pstrString[iActualStart]))
		iActualStart ++;
	while(iActualEnd>=0 && IsCharWhitespace(pstrString[iActualEnd]))
		iActualEnd --;

	int iIndex = 0;
	for( ; iActualStart<=iActualEnd; iActualStart++,iIndex++ ){
		pstrString[iIndex] = pstrString[iActualStart];
	}
	pstrString[iIndex] = '\n';
	pstrString[iIndex+1] = '\0';
}

int SkipToNextLine (){
	++ g_Lexer.iCurrSourceLine;
	if ( g_Lexer.iCurrSourceLine >= g_iSourceCodeSize )
		return FALSE;

	g_Lexer.iIndex0 = 0;
	g_Lexer.iIndex1 = 0;

	g_Lexer.iCurrLexState = LEX_STATE_NO_STRING;
//	printf("\n");
	return TRUE;
}

Token GetNextToken (){
	if (g_Lexer.iCurrSourceLine >= g_iSourceCodeSize)
		return END_OF_TOKEN_STREAM;

	g_Lexer.CurrToken = TOKEN_TYPE_INVALID;//初始化置为无效TOKEN
	char * pCurrLine = g_ppstrSourceCode[g_Lexer.iCurrSourceLine];

	if( g_Lexer.iCurrLexState == LEX_STATE_IN_STRING ){//在引号里面 找到结尾引号
		while(TRUE){
			if ( pCurrLine[g_Lexer.iIndex1]=='\0' )
				ExitOnError("Reach NULL Character\n");
			if ( pCurrLine[g_Lexer.iIndex1]=='"' && pCurrLine[g_Lexer.iIndex1-1]!='\\'){
				copyStr( g_Lexer.pstrCurrLexeme, pCurrLine, g_Lexer.iIndex0, g_Lexer.iIndex1-1 );
				//g_Lexer.iCurrLexState = LEX_STATE_NO_STRING;
				g_Lexer.iCurrLexState = (g_Lexer.iCurrLexState+1)%3;
				g_Lexer.iIndex0 = g_Lexer.iIndex1;
				g_Lexer.CurrToken = TOKEN_TYPE_STRING;
//				printf("String: %s\n", g_Lexer.pstrCurrLexeme);
				return TOKEN_TYPE_STRING;
			}
			g_Lexer.iIndex1 ++;
		}
	}
	
	while( IsCharWhitespace (pCurrLine[g_Lexer.iIndex0]) )
                g_Lexer.iIndex0 ++;

	if(IsCharDelimiter( pCurrLine[g_Lexer.iIndex0] )){
//		printf("Delimiter: %c\n", pCurrLine[g_Lexer.iIndex0]);
		switch (pCurrLine[g_Lexer.iIndex0]){
		case ',':
			g_Lexer.CurrToken = TOKEN_TYPE_COMMA;
			break;
		case ':':
			g_Lexer.CurrToken = TOKEN_TYPE_COLON;
			break;
		case '[':
			g_Lexer.CurrToken = TOKEN_TYPE_OPEN_BRACKET;
			break;
		case ']':
			g_Lexer.CurrToken = TOKEN_TYPE_CLOSE_BRACKET;
			break;
		case '{':
			g_Lexer.CurrToken = TOKEN_TYPE_OPEN_BRACE;
			break;
		case '}':
			g_Lexer.CurrToken = TOKEN_TYPE_CLOSE_BRACE;
			break;
		case '\n':
			g_Lexer.CurrToken = TOKEN_TYPE_NEWLINE;
			copyStr( g_Lexer.pstrCurrLexeme, pCurrLine, g_Lexer.iIndex0, g_Lexer.iIndex0 );
//			SkipToNextLine();
			return g_Lexer.CurrToken;
		case '"':
			g_Lexer.CurrToken = TOKEN_TYPE_QUOTE;
			g_Lexer.iCurrLexState = (g_Lexer.iCurrLexState+1)%3;
			break;
		}
		g_Lexer.iIndex1 = g_Lexer.iIndex0 + 1;
		copyStr( g_Lexer.pstrCurrLexeme, pCurrLine, g_Lexer.iIndex0, g_Lexer.iIndex1-1 );
		g_Lexer.iIndex0 = g_Lexer.iIndex1;
		return g_Lexer.CurrToken;
	}

	g_Lexer.iIndex1 = g_Lexer.iIndex0;
	while( !IsCharDelimiter( pCurrLine[g_Lexer.iIndex1 ] ) ) {
		g_Lexer.iIndex1 ++;
	}
	copyStr( g_Lexer.pstrCurrLexeme, pCurrLine, g_Lexer.iIndex0, g_Lexer.iIndex1-1 );
	g_Lexer.iIndex0 = g_Lexer.iIndex1;

	strupr( g_Lexer.pstrCurrLexeme );
        if ( IsStringInt ( g_Lexer.pstrCurrLexeme ) ) 
                g_Lexer.CurrToken = TOKEN_TYPE_INT;
        if ( IsStringFloat ( g_Lexer.pstrCurrLexeme ) ) 
                g_Lexer.CurrToken = TOKEN_TYPE_FLOAT;
        if ( IsStringIdent ( g_Lexer.pstrCurrLexeme ) ) 
                g_Lexer.CurrToken = TOKEN_TYPE_IDENT;

	if ( strcmp ( g_Lexer.pstrCurrLexeme, "SETSTACKSIZE" ) == 0 )
		g_Lexer.CurrToken = TOKEN_TYPE_SETSTACKSIZE;
	if ( strcmp ( g_Lexer.pstrCurrLexeme, "VAR" ) == 0 )
		g_Lexer.CurrToken = TOKEN_TYPE_VAR;
	if ( strcmp ( g_Lexer.pstrCurrLexeme, "FUNC" ) == 0 )
		g_Lexer.CurrToken = TOKEN_TYPE_FUNC;
	if ( strcmp ( g_Lexer.pstrCurrLexeme, "PARAM" ) == 0 )
		g_Lexer.CurrToken = TOKEN_TYPE_PARAM;
	if ( strcmp ( g_Lexer.pstrCurrLexeme, "_RETVAL" ) == 0 )
		g_Lexer.CurrToken = TOKEN_TYPE_REG_RETVAL;
	InstrLookup Instr;
	if ( GetInstrByMnemonic ( g_Lexer.pstrCurrLexeme, & Instr ) )
		g_Lexer.CurrToken = TOKEN_TYPE_INSTR;

//	if(strlen(g_Lexer.pstrCurrLexeme)==0)
//		printf("NULL:%d ",g_Lexer.CurrToken);
//	else
//		printf("%s:%d ", g_Lexer.pstrCurrLexeme, g_Lexer.CurrToken);
	return g_Lexer.CurrToken;
}

char GetLookAheadChar(){
	int iCurrSourceLine = g_Lexer.iCurrSourceLine;
	int index = g_Lexer.iIndex1;
	while(TRUE){
		if( iCurrSourceLine >= g_iSourceCodeSize )
			return NULL;
		if( index >= strlen( g_ppstrSourceCode[iCurrSourceLine] ) ){
			index = 0;
			iCurrSourceLine ++;
		}
		if( !IsCharWhitespace(g_ppstrSourceCode[iCurrSourceLine][index]) )
			break;
		index ++;
	}
	return g_ppstrSourceCode[iCurrSourceLine][index];
}

	
void AssmblSourceFile (){
	g_ScriptHeader.iStackSize = 0;
	g_ScriptHeader.iIsMainFuncPresent = FALSE;
	g_iInstrStreamSize = 0;
	g_iIsSetStackSizeFound = FALSE;
	g_ScriptHeader.iGlobalDataSize = 0;
	int iIsFuncActive = FALSE;
	FuncNode * pCurrFunc;
	int iCurrFuncIndex;
	char pstrCurrFuncName [ MAX_IDENT_SIZE ];
	int iCurrFuncParamCount = 0;
	int iCurrFuncLocalDataSize = 0;
	InstrLookup CurrInstr;
	
	ResetLexer ();

	while(TRUE){
		if ( GetNextToken () == END_OF_TOKEN_STREAM )
			break;

		switch ( g_Lexer.CurrToken ){
			case TOKEN_TYPE_SETSTACKSIZE:{
			if ( iIsFuncActive )
				ExitOnCodeError ( ERROR_MSSG_LOCAL_SETSTACKSIZE );
			if ( g_iIsSetStackSizeFound )
				ExitOnCodeError ( ERROR_MSSG_MULTIPLE_SETSTACKSIZES );
			if ( GetNextToken () != TOKEN_TYPE_INT )
				ExitOnCodeError ( ERROR_MSSG_INVALID_STACK_SIZE );

			g_ScriptHeader.iStackSize = atoi ( GetCurrLexeme () );
			g_iIsSetStackSizeFound = TRUE;
			break;
			}

			case TOKEN_TYPE_VAR:{
			if ( GetNextToken () != TOKEN_TYPE_IDENT )
			    ExitOnCodeError ( ERROR_MSSG_IDENT_EXPECTED );
			
			char pstrIdent [ MAX_IDENT_SIZE ];
			strcpy ( pstrIdent, GetCurrLexeme () );
			
			int iSize = 1;
			
			if ( GetLookAheadChar () == '[' )
			{
			    if ( GetNextToken () != TOKEN_TYPE_OPEN_BRACKET )
			        ExitOnCharExpectedError ( '[' );
			    if ( GetNextToken () != TOKEN_TYPE_INT )
			        ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY_SIZE );
			
			    iSize = atoi ( GetCurrLexeme () );
			    if ( iSize <= 0 )
			        ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY_SIZE );
			    if ( GetNextToken () != TOKEN_TYPE_CLOSE_BRACKET )
			        ExitOnCharExpectedError ( ']' );
			}
			
			int iStackIndex;
			if ( iIsFuncActive )
			    iStackIndex = -( iCurrFuncLocalDataSize + 2 );
			else
			    iStackIndex = g_ScriptHeader.iGlobalDataSize;
			
			if ( AddSymbol ( pstrIdent, iSize, iStackIndex, iCurrFuncIndex ) == -1 )
			    ExitOnCodeError ( ERROR_MSSG_IDENT_REDEFINITION );
			
			if ( iIsFuncActive )
			    iCurrFuncLocalDataSize += iSize;
			else
			    g_ScriptHeader.iGlobalDataSize += iSize;
			
			break;
			}

			case TOKEN_TYPE_FUNC:{
			if ( iIsFuncActive )
			    ExitOnCodeError ( ERROR_MSSG_NESTED_FUNC );
			
			if ( GetNextToken () != TOKEN_TYPE_IDENT )
			    ExitOnCodeError ( ERROR_MSSG_IDENT_EXPECTED );
			
			char * pstrFuncName = GetCurrLexeme ();
			int iEntryPoint = g_iInstrStreamSize;
			int iFuncIndex = AddFunc ( pstrFuncName, iEntryPoint );
			if ( iFuncIndex == -1 )
			    ExitOnCodeError ( ERROR_MSSG_FUNC_REDEFINITION );
			
			if ( strcmp ( pstrFuncName, MAIN_FUNC_NAME ) == 0 )
			{
			    g_ScriptHeader.iIsMainFuncPresent = TRUE;
				g_ScriptHeader.iMainFuncIndex = iFuncIndex;
			}
			
			iIsFuncActive = TRUE;
			strcpy ( pstrCurrFuncName, pstrFuncName );
			iCurrFuncIndex = iFuncIndex;
			iCurrFuncParamCount = 0;
			iCurrFuncLocalDataSize = 0;
			
			while ( GetNextToken () == TOKEN_TYPE_NEWLINE ){
				SkipToNextLine();
			};
			
			if ( g_Lexer.CurrToken != TOKEN_TYPE_OPEN_BRACE )
			    ExitOnCharExpectedError ( '{' );
			
			break;
			}

			case TOKEN_TYPE_CLOSE_BRACE:{
			if ( ! iIsFuncActive )
				ExitOnCodeError("Not In A Function");

			SetFuncInfo ( pstrCurrFuncName, iCurrFuncParamCount, iCurrFuncLocalDataSize );		
			++ g_iInstrStreamSize;
			iIsFuncActive = FALSE;
			break;
			}

			case TOKEN_TYPE_PARAM:{
			if ( ! iIsFuncActive )
			    ExitOnCodeError ( ERROR_MSSG_GLOBAL_PARAM );
			
			if ( strcmp ( pstrCurrFuncName, MAIN_FUNC_NAME ) == 0 )
				ExitOnCodeError ( ERROR_MSSG_MAIN_PARAM );
			
			if ( GetNextToken () != TOKEN_TYPE_IDENT )
			    ExitOnCodeError ( ERROR_MSSG_IDENT_EXPECTED );
			
			++ iCurrFuncParamCount;
			
			break;
			}

			case TOKEN_TYPE_INSTR:{
			if ( ! iIsFuncActive )
			    ExitOnCodeError ( ERROR_MSSG_GLOBAL_INSTR );
			
			++ g_iInstrStreamSize;
			break;
			}

			case TOKEN_TYPE_IDENT:{
			if ( GetLookAheadChar () != ':' )
			    ExitOnCodeError ( ERROR_MSSG_INVALID_INSTR );
			if ( ! iIsFuncActive )
			    ExitOnCodeError ( ERROR_MSSG_GLOBAL_LINE_LABEL );
			
			char * pstrIdent = GetCurrLexeme ();
			int iTargetIndex = g_iInstrStreamSize;
			
			int iFuncIndex = iCurrFuncIndex;
			if ( AddLabel ( pstrIdent, iTargetIndex, iFuncIndex ) == -1 )
			    ExitOnCodeError ( ERROR_MSSG_LINE_LABEL_REDEFINITION );
			
			break;
			}

			default:
			if ( g_Lexer.CurrToken != TOKEN_TYPE_NEWLINE )
			    ExitOnCodeError ( ERROR_MSSG_INVALID_INPUT );
		}

		if ( ! SkipToNextLine () )
                	break;
	}

	//第二遍
	g_pInstrStream = ( Instr * ) malloc ( g_iInstrStreamSize * sizeof ( Instr ) );
	int iCurrInstrIndex = 0;
	for ( ; iCurrInstrIndex < g_iInstrStreamSize; ++ iCurrInstrIndex )
	    g_pInstrStream [ iCurrInstrIndex ].pOpList = NULL;
	g_iCurrInstrIndex = 0;
	ResetLexer ();

	while(TRUE){
		if ( GetNextToken () == END_OF_TOKEN_STREAM )
			break;

		switch ( g_Lexer.CurrToken ){
			case TOKEN_TYPE_FUNC:{
				GetNextToken ();
				pCurrFunc = GetFuncByName ( GetCurrLexeme () );
				iIsFuncActive = TRUE;
				iCurrFuncParamCount = 0;
				iCurrFuncIndex = pCurrFunc->iIndex;

				while ( GetNextToken () == TOKEN_TYPE_NEWLINE ){
					SkipToNextLine();
				};
				break;
			}

			case TOKEN_TYPE_CLOSE_BRACE:{
				iIsFuncActive = FALSE;
				if ( strcmp ( pCurrFunc->pstrName, MAIN_FUNC_NAME ) == 0 ){
					g_pInstrStream [ g_iCurrInstrIndex ].iOpcode = INSTR_EXIT;
					g_pInstrStream [ g_iCurrInstrIndex ].iOpCount = 1;
					g_pInstrStream [ g_iCurrInstrIndex ].pOpList = ( Op * ) malloc ( sizeof ( Op ) );
                        		g_pInstrStream [ g_iCurrInstrIndex ].pOpList [ 0 ].iType = OP_TYPE_INT;
                        		g_pInstrStream [ g_iCurrInstrIndex ].pOpList [ 0 ].iValue = 0;
				}else{
					g_pInstrStream [ g_iCurrInstrIndex ].iOpcode = INSTR_RET;
					g_pInstrStream [ g_iCurrInstrIndex ].iOpCount = 0;
					g_pInstrStream [ g_iCurrInstrIndex ].pOpList = NULL;
				}
				++ g_iCurrInstrIndex;
				break;
			}

			case TOKEN_TYPE_PARAM:{
				if ( GetNextToken () != TOKEN_TYPE_IDENT )
					ExitOnCodeError ( ERROR_MSSG_IDENT_EXPECTED );

				char * pstrIdent = GetCurrLexeme ();
				int iStackIndex = -( pCurrFunc->iLocalDataSize + 2 + ( iCurrFuncParamCount + 1 ) );
				if ( AddSymbol ( pstrIdent, 1, iStackIndex, iCurrFuncIndex ) == -1 )
					ExitOnCodeError ( ERROR_MSSG_IDENT_REDEFINITION );

				++ iCurrFuncParamCount;
				break;
			}

			case TOKEN_TYPE_INSTR:{
				GetInstrByMnemonic ( GetCurrLexeme (), & CurrInstr );
				g_pInstrStream [ g_iCurrInstrIndex ].iOpcode = CurrInstr.iOpcode;
				g_pInstrStream [ g_iCurrInstrIndex ].iOpCount = CurrInstr.iOpCount;
				Op * pOpList = ( Op * ) malloc ( CurrInstr.iOpCount * sizeof ( Op ) );

				int iCurrOpIndex = 0;
				for( ; iCurrOpIndex < CurrInstr.iOpCount; ++ iCurrOpIndex ){
					OpTypes CurrOpTypes = CurrInstr.OpList [ iCurrOpIndex ];
					Token InitOpToken = GetNextToken ();

					switch ( InitOpToken ){
						case TOKEN_TYPE_INT:{
							if( CurrOpTypes & OP_FLAG_TYPE_INT ){
								pOpList [ iCurrOpIndex ].iType = OP_TYPE_INT;
								pOpList [ iCurrOpIndex ].iValue = atoi ( GetCurrLexeme () );
							}else
								ExitOnCodeError ( ERROR_MSSG_INVALID_OP );

							break;
						}
						case TOKEN_TYPE_FLOAT:{
							if ( CurrOpTypes & OP_FLAG_TYPE_FLOAT ){
								pOpList [ iCurrOpIndex ].iType = OP_TYPE_FLOAT;
								pOpList [ iCurrOpIndex ].fValue = ( float ) atof ( GetCurrLexeme () );
							}else
								ExitOnCodeError ( ERROR_MSSG_INVALID_OP );

							break;
						}
						case TOKEN_TYPE_QUOTE:{
							if ( CurrOpTypes & OP_FLAG_TYPE_STRING ){
								GetNextToken ();
								switch ( g_Lexer.CurrToken ){
									case TOKEN_TYPE_QUOTE:{
										pOpList [ iCurrOpIndex ].iType = OP_TYPE_INT;
										pOpList [ iCurrOpIndex ].iValue = 0;
										break;
									}
									case TOKEN_TYPE_STRING:{
										char * pstrString = GetCurrLexeme ();
										int iStringIndex = AddString ( & g_StringTable, pstrString );
										if ( GetNextToken () != TOKEN_TYPE_QUOTE )
											ExitOnCharExpectedError ( '"' );
										pOpList [ iCurrOpIndex ].iType = OP_TYPE_STRING;
										pOpList [ iCurrOpIndex ].iValue = iStringIndex;
										break;
									}
									default:
										ExitOnCodeError ( ERROR_MSSG_INVALID_STRING );
								}
							}else
								ExitOnCodeError ( ERROR_MSSG_INVALID_OP );

							break;
						}
						case TOKEN_TYPE_REG_RETVAL:{
							if ( CurrOpTypes & OP_FLAG_TYPE_REG ){
								pOpList [ iCurrOpIndex ].iType = OP_TYPE_REG;
								pOpList [ iCurrOpIndex ].iValue = 0;
							}else
								ExitOnCodeError ( ERROR_MSSG_INVALID_OP );

							break;
						}
						case TOKEN_TYPE_IDENT:{
							if ( CurrOpTypes & OP_FLAG_TYPE_MEM_REF ){
								char pstrIdent [ MAX_IDENT_SIZE ];
								strcpy ( pstrIdent, GetCurrLexeme () );
								if ( ! GetSymbolByIdent ( pstrIdent, iCurrFuncIndex ) )
									ExitOnCodeError ( ERROR_MSSG_UNDEFINED_IDENT );

								int iBaseIndex = GetStackIndexByIdent ( pstrIdent, iCurrFuncIndex );
								if ( GetLookAheadChar () != '[' ){
									if ( GetSizeByIdent ( pstrIdent, iCurrFuncIndex ) > 1 )
										ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY_NOT_INDEXED );

									pOpList [ iCurrOpIndex ].iType = OP_TYPE_ABS_STACK_INDEX;
									pOpList [ iCurrOpIndex ].iValue = iBaseIndex;
								}else{
									if ( GetSizeByIdent ( pstrIdent, iCurrFuncIndex ) == 1 )
										ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY );

									if ( GetNextToken () != TOKEN_TYPE_OPEN_BRACKET )
										ExitOnCharExpectedError ( '[' );

									Token IndexToken = GetNextToken ();
									if ( IndexToken == TOKEN_TYPE_INT ){
										int iOffsetIndex = atoi ( GetCurrLexeme () );
										pOpList [ iCurrOpIndex ].iType = OP_TYPE_ABS_STACK_INDEX;
										if(iBaseIndex >= 0)
											pOpList [ iCurrOpIndex ].iValue = iBaseIndex + iOffsetIndex;//全局变量
										else
											pOpList [ iCurrOpIndex ].iValue = iBaseIndex - iOffsetIndex;//局部变量
									}else if ( IndexToken == TOKEN_TYPE_IDENT ){
										char * pstrIndexIdent = GetCurrLexeme ();
										if ( ! GetSymbolByIdent ( pstrIndexIdent, iCurrFuncIndex ) )
											ExitOnCodeError ( ERROR_MSSG_UNDEFINED_IDENT );
										if ( GetSizeByIdent ( pstrIndexIdent, iCurrFuncIndex ) > 1 )//>1表示数组变量
											ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY_INDEX );

										int iOffsetIndex = GetStackIndexByIdent ( pstrIndexIdent, iCurrFuncIndex );
										pOpList [ iCurrOpIndex ].iType = OP_TYPE_REL_STACK_INDEX;
										pOpList [ iCurrOpIndex ].iValue = iBaseIndex;
										pOpList [ iCurrOpIndex ].iOffsetIndex = iOffsetIndex;
									}else
										ExitOnCodeError ( ERROR_MSSG_INVALID_ARRAY_INDEX );

									if ( GetNextToken () != TOKEN_TYPE_CLOSE_BRACKET )
										ExitOnCharExpectedError ( ']' );
								}
							}

							if ( CurrOpTypes & OP_FLAG_TYPE_LINE_LABEL ){
								char * pstrLabelIdent = GetCurrLexeme ();
								LabelNode * pLabel = GetLabelByIdent ( pstrLabelIdent, iCurrFuncIndex );
								if ( ! pLabel )
									ExitOnCodeError ( ERROR_MSSG_UNDEFINED_LINE_LABEL );

								pOpList [ iCurrOpIndex ].iType = OP_TYPE_INSTR_INDEX;
								pOpList [ iCurrOpIndex ].iValue = pLabel->iTargetIndex;
							}

							if ( CurrOpTypes & OP_FLAG_TYPE_FUNC_NAME ){
								char * pstrFuncName = GetCurrLexeme ();
								FuncNode * pFunc = GetFuncByName ( pstrFuncName );
								if ( ! pFunc )
									ExitOnCodeError ( ERROR_MSSG_UNDEFINED_FUNC );

								pOpList [ iCurrOpIndex ].iType = OP_TYPE_FUNC_INDEX;
								pOpList [ iCurrOpIndex ].iValue = pFunc->iIndex;
							}

							if ( CurrOpTypes & OP_FLAG_TYPE_HOST_API_CALL ){
								char * pstrHostAPICall = GetCurrLexeme ();
								int iIndex = AddString ( & g_HostAPICallTable, pstrHostAPICall );
								pOpList [ iCurrOpIndex ].iType = OP_TYPE_HOST_API_CALL_INDEX;
								pOpList [ iCurrOpIndex ].iValue = iIndex;
							}

							break;
						}

						default:
							ExitOnCodeError ( ERROR_MSSG_INVALID_OP );
							break;

					}
					if ( iCurrOpIndex < CurrInstr.iOpCount - 1 )
						if ( GetNextToken () != TOKEN_TYPE_COMMA )
							ExitOnCharExpectedError ( ',' );
				}
				if ( GetNextToken () != TOKEN_TYPE_NEWLINE )
					ExitOnCodeError ( ERROR_MSSG_INVALID_INPUT );
				g_pInstrStream [ g_iCurrInstrIndex ].pOpList = pOpList;
				++ g_iCurrInstrIndex;
				break;
			}
		}
		if ( ! SkipToNextLine () )
			break;
	}
}

void BuildXSE (char * g_pstrExecFilename){
	FILE * pExecFile;
	if ( ! ( pExecFile = fopen ( g_pstrExecFilename, "wb" ) ) )
		ExitOnError ( "Could not open executable file for output" );

	fwrite ( XSE_ID_STRING, 4, 1, pExecFile );

	char cVersionMajor = 1, cVersionMinor = 0;
	fwrite ( & cVersionMajor, 1, 1, pExecFile );
	fwrite ( & cVersionMinor, 1, 1, pExecFile );

	fwrite ( & g_ScriptHeader.iStackSize, 4, 1, pExecFile );
	fwrite ( & g_ScriptHeader.iGlobalDataSize, 4, 1, pExecFile );

	char cIsMainPresent = 0;
	if ( g_ScriptHeader.iIsMainFuncPresent )
		cIsMainPresent = 1;
	fwrite ( & cIsMainPresent, 1, 1, pExecFile );

	fwrite ( & g_ScriptHeader.iMainFuncIndex, 4, 1, pExecFile );
	fwrite ( & g_iInstrStreamSize, 4, 1, pExecFile );

	int iCurrInstrIndex = 0;
	for( ; iCurrInstrIndex < g_iInstrStreamSize; ++ iCurrInstrIndex ){
		short sOpcode = g_pInstrStream [ iCurrInstrIndex ].iOpcode;
		fwrite ( & sOpcode, 2, 1, pExecFile );

		char iOpCount = g_pInstrStream [ iCurrInstrIndex ].iOpCount;
		fwrite ( & iOpCount, 1, 1, pExecFile );

		int iCurrOpIndex = 0;
		for ( ; iCurrOpIndex < iOpCount; ++ iCurrOpIndex ){
			Op CurrOp = g_pInstrStream [ iCurrInstrIndex ].pOpList [ iCurrOpIndex ];
			char cOpType = CurrOp.iType;
			fwrite ( & cOpType, 1, 1, pExecFile );

			switch ( CurrOp.iType ){
				case OP_TYPE_INT:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_FLOAT:
				fwrite ( & CurrOp.fValue, sizeof ( float ), 1, pExecFile );
				break;

				case OP_TYPE_STRING:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_INSTR_INDEX:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_ABS_STACK_INDEX:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_REL_STACK_INDEX:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_FUNC_INDEX:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_HOST_API_CALL_INDEX:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;

				case OP_TYPE_REG:
				fwrite ( & CurrOp.iValue, sizeof ( int ), 1, pExecFile );
				break;
			}
		}
	}

	int iCurrNode;
	LinkedListNode * pNode;
	fwrite ( & g_StringTable.iNodeCount, 4, 1, pExecFile );
	pNode = g_StringTable.pHead;
	for ( iCurrNode = 0; iCurrNode < g_StringTable.iNodeCount; ++ iCurrNode ){
		char * pstrCurrString = ( char * ) pNode->pData;
		int iCurrStringLength = strlen ( pstrCurrString );

		fwrite ( & iCurrStringLength, 4, 1, pExecFile );
		fwrite ( pstrCurrString, strlen ( pstrCurrString ), 1, pExecFile );

		pNode = pNode->pNext;
	}

	fwrite ( & g_FuncTable.iNodeCount, 4, 1, pExecFile );
	pNode = g_FuncTable.pHead;
	char cParamCount;
	for ( iCurrNode = 0; iCurrNode < g_FuncTable.iNodeCount; ++ iCurrNode ){
		FuncNode * pFunc = ( FuncNode * ) pNode->pData;
		fwrite ( & pFunc->iEntryPoint, sizeof ( int ), 1, pExecFile );

		cParamCount = pFunc->iParamCount;
		fwrite ( & cParamCount, 1, 1, pExecFile );
		fwrite ( & pFunc->iLocalDataSize, sizeof ( int ), 1, pExecFile );

		pNode = pNode->pNext;
	}
	
	fwrite ( & g_HostAPICallTable.iNodeCount, 4, 1, pExecFile );
	pNode = g_HostAPICallTable.pHead;
	for ( iCurrNode = 0; iCurrNode < g_HostAPICallTable.iNodeCount; ++ iCurrNode ){
		char * pstrCurrHostAPICall = ( char * ) pNode->pData;
		char cCurrHostAPICallLength = strlen ( pstrCurrHostAPICall );

		fwrite ( & cCurrHostAPICallLength, 1, 1, pExecFile );
		fwrite ( pstrCurrHostAPICall, cCurrHostAPICallLength, 1, pExecFile );

		pNode = pNode->pNext;
	}

	fclose ( pExecFile );
}

int AddString ( LinkedList * pList, char * pstrString ){
	LinkedListNode * pNode = pList->pHead;
	int index=0;
	for(; index<pList->iNodeCount; ++ index){
		if ( strcmp ( ( char * ) pNode->pData, pstrString ) == 0 )
			return index;

		pNode = pNode->pNext;
	}

	char * pstrStringNode = ( char * ) malloc ( strlen ( pstrString ) + 1 );
	strcpy ( pstrStringNode, pstrString );

	return AddNode ( pList, pstrStringNode );
}

int AddFunc ( char * pstrName, int iEntryPoint ){
	if ( GetFuncByName ( pstrName ) )
		return -1;

	FuncNode * pNewFunc = ( FuncNode * ) malloc ( sizeof ( FuncNode ) );
	strcpy ( pNewFunc->pstrName, pstrName );
	pNewFunc->iEntryPoint = iEntryPoint;

	int iIndex = AddNode ( &g_FuncTable, pNewFunc);
	pNewFunc->iIndex = iIndex;

	return iIndex;
}

void SetFuncInfo ( char * pstrName, int iParamCount, int iLocalDataSize ){
	FuncNode * pFunc = GetFuncByName ( pstrName );
	pFunc->iParamCount = iParamCount;
	pFunc->iLocalDataSize = iLocalDataSize;
}

FuncNode * GetFuncByName ( char * pstrName ){
	if ( g_FuncTable.iNodeCount==0 )
            return NULL;

	LinkedListNode * pCurrNode = g_FuncTable.pHead;

	int index = 0;
	for(; index<g_FuncTable.iNodeCount; index++){
		FuncNode * pCurrFunc = ( FuncNode * ) pCurrNode->pData;
		if ( strcmp(pCurrFunc->pstrName, pstrName)==0 )
			return pCurrFunc;

		pCurrNode = pCurrNode->pNext;
	}

	return NULL;
}

int AddSymbol ( char * pstrIdent, int iSize, int iStackIndex, int iFuncIndex ) {

	if ( GetSymbolByIdent ( pstrIdent, iFuncIndex ) )
		return -1;

	SymbolNode * pNewSymbol = ( SymbolNode * ) malloc ( sizeof ( SymbolNode ) );
	strcpy ( pNewSymbol->pstrIdent, pstrIdent );
	pNewSymbol->iSize = iSize;
	pNewSymbol->iStackIndex = iStackIndex;
	pNewSymbol->iFuncIndex = iFuncIndex;

	int iIndex = AddNode ( & g_SymbolTable, pNewSymbol );
	pNewSymbol->iIndex = iIndex;

	return iIndex;
}

SymbolNode * GetSymbolByIdent ( char * pstrIdent, int iFuncIndex ){

	if ( ! g_SymbolTable.iNodeCount )
		return NULL;

	LinkedListNode * pCurrNode = g_SymbolTable.pHead;
	int iCurrNode = 0;
	for ( ; iCurrNode < g_SymbolTable.iNodeCount; ++ iCurrNode ){
		SymbolNode * pCurrSymbol = ( SymbolNode * ) pCurrNode->pData;
		if ( strcmp ( pCurrSymbol->pstrIdent, pstrIdent ) == 0 )
			if ( pCurrSymbol->iFuncIndex == iFuncIndex || pCurrSymbol->iStackIndex >= 0 )
				return pCurrSymbol;

		pCurrNode = pCurrNode->pNext;
	}
	return NULL;
}

int GetStackIndexByIdent ( char * pstrIdent, int iFuncIndex ){
	SymbolNode * pSymbol = GetSymbolByIdent ( pstrIdent, iFuncIndex );
	return pSymbol->iStackIndex;
}

int GetSizeByIdent ( char * pstrIdent, int iFuncIndex ){
	SymbolNode * pSymbol = GetSymbolByIdent ( pstrIdent, iFuncIndex );
	return pSymbol->iSize;
}

int AddLabel ( char * pstrIdent, int iTargetIndex, int iFuncIndex ){
	if ( GetLabelByIdent( pstrIdent, iFuncIndex ) )
		return -1;

	LabelNode * pNewLabel = ( LabelNode * ) malloc ( sizeof ( LabelNode ) );
	strcpy ( pNewLabel->pstrIdent, pstrIdent );
	pNewLabel->iTargetIndex = iTargetIndex;
	pNewLabel->iFuncIndex = iFuncIndex;

	int iIndex = AddNode( & g_LabelTable, pNewLabel );
	pNewLabel->iIndex = iIndex;

	return iIndex;
}

LabelNode * GetLabelByIdent ( char * pstrIdent, int iFuncIndex ){
	if( !g_LabelTable.iNodeCount )
		return NULL;

	LinkedListNode * pCurrNode = g_LabelTable.pHead;
	int iCurrNode = 0;
	for( ; iCurrNode < g_LabelTable.iNodeCount; ++ iCurrNode ){
		LabelNode * pCurrLabel = ( LabelNode * )pCurrNode->pData;
		if( strcmp ( pCurrLabel->pstrIdent, pstrIdent) == 0  && pCurrLabel->iFuncIndex == iFuncIndex )
			return pCurrLabel;

		pCurrNode = pCurrNode->pNext; 
	}

	return NULL;
}

void ResetLexer (){
	g_Lexer.iCurrSourceLine = 0;
	g_Lexer.iIndex0 = 0;
	g_Lexer.iIndex1 = 0;
	g_Lexer.CurrToken = TOKEN_TYPE_INVALID;
	g_Lexer.iCurrLexState = LEX_STATE_NO_STRING;
}

char * GetCurrLexeme (){
	return g_Lexer.pstrCurrLexeme;
}

void ExitOnError(char * msg){
	printf("ERROR: %s\n");
	exit(0);
}

void ExitOnCodeError ( char * pstrErrorMssg ){
	printf ( "Error: %s.\n\n", pstrErrorMssg );
	printf ( "Line %d\n", g_Lexer.iCurrSourceLine );

	char pstrSourceLine [ MAX_SOURCE_LINE_SIZE ];
	strcpy ( pstrSourceLine, g_ppstrSourceCode [ g_Lexer.iCurrSourceLine ] );

	int iCurrCharIndex = 0;
	for(; iCurrCharIndex < strlen ( pstrSourceLine ); ++ iCurrCharIndex )
		if ( pstrSourceLine [ iCurrCharIndex ] == '\t' )
			pstrSourceLine [ iCurrCharIndex ] = ' ';

	printf ( "%s", pstrSourceLine );
	int iCurrSpace = 0;
	for(; iCurrSpace < g_Lexer.iIndex0; ++ iCurrSpace )
		printf ( " " );
	printf ( "^\n" );

	printf ( "Could not assemble .\n" );

	ShutDown ();
	exit(0);
}

void ExitOnCharExpectedError ( char cChar ){
	char * pstrErrorMssg = ( char * ) malloc ( strlen ( "' ' expected" ) );
	sprintf ( pstrErrorMssg, "'%c' expected", cChar );
	ExitOnCodeError ( pstrErrorMssg );
}

void ShutDown (){
	int iCurrLineIndex = 0;
    for ( ; iCurrLineIndex < g_iSourceCodeSize; ++ iCurrLineIndex )
        free ( g_ppstrSourceCode [ iCurrLineIndex ] ); 
    free ( g_ppstrSourceCode );

	if ( g_pInstrStream ) {
		int iCurrInstrIndex = 0;
		for ( ; iCurrInstrIndex < g_iInstrStreamSize; ++ iCurrInstrIndex )
				if ( g_pInstrStream [ iCurrInstrIndex ].pOpList )
						free ( g_pInstrStream [ iCurrInstrIndex ].pOpList );
	
		free ( g_pInstrStream );
	}
	
	FreeLinkedList ( & g_SymbolTable );
	FreeLinkedList ( & g_LabelTable );
	FreeLinkedList ( & g_FuncTable );
	FreeLinkedList ( & g_StringTable );
	FreeLinkedList ( & g_HostAPICallTable );
}
